package com.ethercamp.harmony.dmt.db.config;

import com.ethercamp.harmony.dmt.db.exception.InitializationException;
import com.ethercamp.harmony.dmt.db.exception.ResourceNotFoundException;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

/**
 * 读取application
 */
@Configuration
public class EthersqlConfig {

    private final Logger logger = LoggerFactory.getLogger("config");


    private static EthersqlConfig ethersqlConfig = new EthersqlConfig();
//    private Config config;
    private ClassLoader classLoader;

    public static EthersqlConfig getDefaultConfig() {
        return ethersqlConfig;
    }

    /**
     * 默认数据库
     */
    @Value("${default.db}")
    private String defaultDB;

    /**
     * mongodb host
     */
    @Value("${mongo.host}")
    private String mongoHost;
    /**
     * mongodb port
     */
    @Value("${mongo.port}")
    private Integer mongoPort;
    /**
     * mongodb 用户名
     */
    @Value("${mongo.username}")
    private String mongoUsername;
    /**
     * mongodb 密码
     */
    @Value("${mongo.password}")
    private String mongoPassword;
    /**
     * mongodb 数据库名
     */
    @Value("${mongo.db}")
    private String mongoDatabase;


    @Value("${analysis.frequency.map}")
    private String frequencyMapPath;
    private String frequencyMap;
    @Value("${analysis.frequency.reduce}")
    private String frequencyReducePath;
    private String frequencyReduce;
    @Value("${analysis.value.map}")
    private String valueMapPath;
    private String valueMap;
    @Value("${analysis.value.reduce}")
    private String valueReducePath;
    private String valueReduce;

    @Value("${database.reset}")
    private Boolean resetDatabase = true;



    public EthersqlConfig(Config config) {
//        Config javaSystemProperties = ConfigFactory.load("no-such-resource-only-system-props");
//        logger.info("loading java system properties");
//        Config userConfig = ConfigFactory.parseResources("ethersql.conf");
//        logger.info("loading user defined ethersql.conf");
        this.classLoader = getClass().getClassLoader();
//        Config defaultConfig = ConfigFactory.load(classLoader, "ethersql.conf");

//        this.config = javaSystemProperties
//                .withFallback(defaultConfig)
//                .withFallback(config.withFallback(userConfig));
        validateConfig();
    }

    public EthersqlConfig(String configLocation) {
        this(ConfigFactory.parseResources(configLocation));
    }

    public EthersqlConfig(File configFile) {
        this(ConfigFactory.parseFile(configFile));
    }

    public EthersqlConfig() {
        this(ConfigFactory.empty());
    }

//    public Config getConfig() {
//        return config;
//    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface ValidateMe {
    }

    private void validateConfig() {
        for (Method method : getClass().getMethods()) {
            if (method.isAnnotationPresent(ValidateMe.class)) {
                try {
                    method.invoke(this);
                } catch (Exception e) {
                    throw new InitializationException("Error validating config" + method, e);
                }
            }
        }
    }

    @ValidateMe
    public String getDefaultDB() {
        return defaultDB;
    }

    public String getMongoHost() {
        return mongoHost;
    }

    public void setMongoHost(String mongoHost) {
        this.mongoHost = mongoHost;
    }

    public Integer getMongoPort() {
        return mongoPort;
    }

    public void setMongoPort(Integer mongoPort) {
        this.mongoPort = mongoPort;
    }

    public String getMongoDatabase() {
        return mongoDatabase;
    }

    public void setMongoDatabase(String mongoDatabase) {
        this.mongoDatabase = mongoDatabase;
    }

    public Boolean getResetDatabase() {
        return resetDatabase;
    }

    public void setResetDatabase(Boolean resetDatabase) {
        this.resetDatabase = resetDatabase;
    }

    public String getMongoUsername() {
        return mongoUsername;
    }

    public void setMongoUsername(String mongoUsername) {
        this.mongoUsername = mongoUsername;
    }

    public String getMongoPassword() {
        return mongoPassword;
    }

    public void setMongoPassword(String mongoPassword) {
        this.mongoPassword = mongoPassword;
    }

    private String load(String location) {
        if(location==null || "".equals(location)){
            return "";
        }
        InputStreamReader isr = new InputStreamReader(classLoader.getResourceAsStream(location));
        StringBuffer content = new StringBuffer();
        char[] buffer = new char[4096];
        try {
            while (isr.read(buffer) > 0) {
                content.append(buffer);
            }
            return content.toString();
        } catch (IOException e) {
            throw new ResourceNotFoundException("Resource not found : " + location, e);
        } finally {
            try {
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @ValidateMe
    public String getFrequencyMap() {
        if (frequencyMap != null) {
            return frequencyMap;
        }
        logger.info("analysis.frequency.map"+frequencyMapPath);
        return frequencyMap = load(frequencyMapPath);
    }

    @ValidateMe
    public String getFrequencyReduce() {
        if (frequencyReduce != null) {
            return frequencyReduce;
        }
        logger.info("analysis.frequency.reduce"+frequencyReducePath);
        return frequencyReduce = load(frequencyReducePath);
    }

    @ValidateMe
    public String getValueMap() {
        if (valueMap != null) {
            return valueMap;
        }
        logger.info("analysis.value.map"+valueMapPath);
        return valueMap = load(valueMapPath);
    }

    @ValidateMe
    public String getValueReduce() {
        if (valueReduce != null) {
            return valueReduce;
        }
        logger.info("analysis.value.reduce"+valueReducePath);
        return valueReduce = load(valueReducePath);
    }
}
